package org.youchan.aco.model;

import java.util.ArrayList;
import java.util.List;

import org.youchan.aco.model.Timeline.TimelineEvent.TimelineEventType;


import com.db4o.Db4o;
import com.db4o.ObjectContainer;
import com.db4o.ObjectSet;
import com.db4o.query.Predicate;

public class Timeline {

	private ObjectContainer mDatabase;
	private List<Message> mMessages;
	private List<TimelineListener> mListenerList;
	
	public Timeline(String dbFile) {
		mDatabase = Db4o.openFile(dbFile);
		mMessages = new ArrayList<Message>(1000);
		mListenerList = new ArrayList<TimelineListener>();
		init();
	}
	
	private boolean addMessage(Message message) {
		ObjectSet<Message> result = mDatabase.get(message);
		if (result.size() == 0) {
			mDatabase.set(message);
			while (mMessages.size() >= 1000) {
				mMessages.remove(0);
			}
			mMessages.add(message);
			return true;
		}
		return false;
	}
	
	@SuppressWarnings("serial")
	private void init() {
		ObjectSet<Message> result = mDatabase.query(new Predicate<Message>() {
			@Override
			public boolean match(Message value) {
				return true;
			}
		});
		mMessages.addAll(result);
		fireTimelineInserted(0, mMessages.size() - 1);
	}
	
	public void add(Message ... messages) {
		int count = 0;
		for (Message message: messages) {
			count += addMessage(message) ? 1 : 0;
		}
		
		if (count > 0) {
			mDatabase.commit();
			fireTimelineInserted(0, count - 1);
		}
	}
	
	public void add(List<Message> messages) {
		int count = 0;
		for (Message message: messages) {
			count += addMessage(message) ? 1 : 0;
		}
		
		if (count > 0) {
			mDatabase.commit();
			fireTimelineInserted(0, count - 1);
		}
	}
	
	public int getCurrentMessageSize() {
		return mMessages.size();
	}
	
	public Message getMessage(int index) {
		return mMessages.get(index);
	}
	
	public void addTimelineListener(TimelineListener listener) {
		mListenerList.add(listener);
	}
	
	public void fireTimelineInserted(int firstIndex, int lastIndex) {
		for (TimelineListener listener: mListenerList) {
			listener.timelineChanged(new TimelineEvent(this, TimelineEventType.INSERTED, firstIndex, lastIndex));
		}
	}
	
	public interface TimelineListener {
		public void timelineChanged(TimelineEvent e);
	}
	
	public static class TimelineEvent {
		public enum TimelineEventType {
			INSERTED;
		}
		
		private Timeline timeline;
		private TimelineEventType eventType;
		private int firstIndex;
		private int lastIndex;
		
		public TimelineEvent(Timeline timeline, TimelineEventType eventType, int firstIndex, int lastIndex) {
			this.timeline = timeline;
			this.eventType = eventType;
			this.firstIndex = firstIndex;
			this.lastIndex = lastIndex;
		}
		
		/**
		 * @return the timeline
		 */
		public Timeline getTimeline() {
			return timeline;
		}
		/**
		 * @param timeline the timeline to set
		 */
		public void setTimeline(Timeline timeline) {
			this.timeline = timeline;
		}
		/**
		 * @return the eventType
		 */
		public TimelineEventType getEventType() {
			return eventType;
		}
		/**
		 * @param eventType the eventType to set
		 */
		public void setEventType(TimelineEventType eventType) {
			this.eventType = eventType;
		}
		/**
		 * @return the firstIndex
		 */
		public int getFirstIndex() {
			return firstIndex;
		}
		/**
		 * @param firstIndex the firstIndex to set
		 */
		public void setFirstIndex(int firstIndex) {
			this.firstIndex = firstIndex;
		}
		/**
		 * @return the lastIndex
		 */
		public int getLastIndex() {
			return lastIndex;
		}
		/**
		 * @param lastIndex the lastIndex to set
		 */
		public void setLastIndex(int lastIndex) {
			this.lastIndex = lastIndex;
		}
		
		
	}
}
